package com.bifrost.service.impl;

import com.bifrost.model.SkuExcelModel;
import com.bifrost.model.ro.KeywordBatchRO;
import com.bifrost.model.ro.KeywordRO;
import com.bifrost.cbentity.SapContractProduct;
import com.bifrost.cbentity.SapProduct;
import com.bifrost.cbrepository.SapProductRepository;
import com.bifrost.cbrepository.SapStoreProductRepository;
import com.bifrost.common.util.HttpRequestUtils;
import com.bifrost.constant.ProductSkuType;
import com.bifrost.constant.ProductSortType;
import com.bifrost.dto.AssignedProductOptionDTO;
import com.bifrost.entity.*;
import com.bifrost.exception.FormatException;
import com.bifrost.exception.KnownRuntimeException;
import com.bifrost.model.MediaModel;
import com.bifrost.model.OptionModel;
import com.bifrost.model.ProductAddModel;
import com.bifrost.model.ProductBasicModel;
import com.bifrost.model.ProductSkuModel;
import com.bifrost.model.option.OptionValueModel;
import com.bifrost.model.ro.ProductImgUploadRO;
import com.bifrost.model.vo.ImgVo;
import com.bifrost.model.vo.PageVO;
import com.bifrost.model.vo.ProductVO;
import com.bifrost.repository.*;
import com.bifrost.service.*;
import com.bifrost.service.ProductService;
import com.bifrost.util.DateUtils;
import com.bifrost.util.FileUploadUtils;
import com.bifrost.util.ServiceUtils;
import com.bifrost.util.StringUtil;
import com.bifrost.util.TransformUtils;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.util.Asserts;
import org.jetbrains.annotations.NotNull;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;

import javax.persistence.criteria.*;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.regex.Matcher;
import java.util.stream.Collectors;

/**
 * @author rangf
 * @date 2018/3/5
 */
@Service
@Slf4j
public class ProductServiceImpl implements ProductService {

    @Autowired
    ProductSkuService productSkuService;
    @Autowired
    ProductRepository productRepository;
    @Autowired
    ProductSkuRepository productSkuRepository;
    @Autowired
    ProductOptionRepository productOptionRepository;
    @Autowired
    CategoryRepository categoryRepository;
    @Autowired
    ProductBrandRepository brandRepository;
    @Autowired
    SkuMediaMapRepository skuMediaMapRepository;
    @Autowired
    SkuOptionValueRepository skuOptionValueRepository;
    @Autowired
    MediaRepository mediaRepository;
    @Autowired
    MediaService mediaService;
    @Autowired
    private SapProductRepository sapProductRepository;
    @Autowired
    AdminUserRepository adminUserRepository;
    @Autowired
    private SapGoodsRepository sapGoodsRepository;
    @Autowired
    SapStoreGoodsRepository sapStoreGoodsRepository;
    @Autowired
    SapStoreProductRepository sapStoreProductRepository;
    @Autowired
    SapContractProductService sapContractProductService;
    @Autowired
    SapContractService sapContractService;
    @Autowired
    StoreService storeService;
    @Autowired
    PriceHistoryRepository priceHistoryRepository;
    @Autowired
    SkuShipmentRepository skuShipmentRepository;
    /**
     * 返回商品所有所有属性值
     *
     * @param product
     * @return
     */
    @Override
    public List getAllProductOptionValues(Product product) {
        List productOptions = null;
        List<AssignedProductOptionDTO> assignedProductOptionDTOList = productSkuService.findAssignedProductOptionsByProduct(product);
        if(CollectionUtils.isNotEmpty(assignedProductOptionDTOList)){
            List<ProductOptionValue> productOptionValueList = assignedProductOptionDTOList.stream().map(AssignedProductOptionDTO::getProductOptionValue).collect(Collectors.toList());
            if(CollectionUtils.isNotEmpty(productOptionValueList)){
                List<ProductOption> optionList = productOptionValueList.stream().map(ProductOptionValue::getProductOption).distinct().collect(Collectors.toList());
                if(CollectionUtils.isNotEmpty(optionList)){
                    productOptions = new ArrayList();
                    for (ProductOption productOption : optionList) {
                        Map optionMap = new HashMap(1);
                        List productOptionValues = null;
                        productOptionValues = new ArrayList();
                        for (ProductOptionValue productOptionValue : productOptionValueList) {
                            if(productOptionValue.getProductOption().getProductOptionId().equals(productOption.getProductOptionId())){
                                String attrValue = productOptionValue.getAttributeValue();
                                if(!productOptionValues.contains(attrValue)){
                                    productOptionValues.add(attrValue);
                                }
                            }
                        }
                        optionMap.put(productOption.getAttributeName(), productOptionValues);
                        productOptions.add(optionMap);
                    }
                }
            }
        }
        return productOptions;
    }

    /**
     * 查询指定的商品
     *
     * @param id
     * @return
     */
    @Override
    public Product findProduct(Long id) {
        return productRepository.findOne(id);
    }

    /**
     * 获取门店指定类别下的商品（默认sku）列表
     *
     * @param store    门店
     * @param page     当前页数
     * @param pageSize 类目Id
     * @param sortType 排序方式
     * @param minPrice 最低价
     * @param maxPrice 最高价
     * @param querykey 搜索关键字
     * @param brandIds 品牌Id字符串数组
     * @return List
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Page getProductsByStore(MerchantStore store,String storeIds , String externalIds, String categoryName,String brandName, Integer page, Integer pageSize, String sortType, String minPrice, String maxPrice, String querykey, String brandIds, String available , Boolean isDefault,Boolean skuAvailable,Boolean skuSaleFlag) {


        Pageable pageable = null;
        //商品排序 0:综合排序，1：价格升序，2：价格降序，3：销量降序
        if (ProductSortType.MULTIPLE.equals(sortType)) {
            List<Sort.Order> orders = new ArrayList<>();
            orders.add(new Sort.Order(Sort.Direction.DESC, "updatedTimestamp"));
            pageable = new PageRequest(page - 1, pageSize, new Sort(orders));
        } else if (ProductSortType.PEICEUP.equals(sortType)) {
            pageable = new PageRequest(page - 1, pageSize, new Sort(Sort.Direction.ASC, "salePrice"));
        } else if (ProductSortType.PRICEDOWN.equals(sortType)) {
            pageable = new PageRequest(page - 1, pageSize, new Sort(Sort.Direction.DESC, "salePrice"));
        } else if (ProductSortType.SALECOUNT.equals(sortType)) {
            pageable = new PageRequest(page - 1, pageSize, new Sort(Sort.Direction.DESC, "saleCount"));
        } else {
            pageable = new PageRequest(page - 1, pageSize);
        }
        Specification<ProductSku> query = createSkuSpecification(store,storeIds,externalIds, categoryName, brandName, minPrice, maxPrice, querykey, brandIds, available , isDefault,skuAvailable,skuSaleFlag);
        return productSkuRepository.findAll(query, pageable);
    }

    private Specification<ProductSku> createSkuSpecification(MerchantStore store, String storeIds, String externalIds, String categoryName, String brandName, String minPrice, String maxPrice, String querykey, String brandIds, String available, Boolean isDefault, Boolean skuAvailable, Boolean skuSaleFlag) {
        return new Specification<ProductSku>() {
            @Override
            public Predicate toPredicate(Root<ProductSku> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                    List<Predicate> predicates = new ArrayList<>();

                    Join<ProductSku, Product> product = root.join("product", JoinType.INNER);
                    Path<Boolean> archived = product.get("archived");
                    predicates.add(cb.or(cb.isFalse(archived),cb.isNull(archived)));

                    //上下架
                    if (StringUtils.isNotBlank(available)) {
                        predicates.add(cb.equal(product.get("available"), Boolean.parseBoolean(available)));
                    }

                    //sku可用
                    if(skuAvailable){
                        predicates.add(cb.isTrue(root.get("available")));
                    }

                    //sku可销售
                    if(skuSaleFlag){
                        predicates.add(cb.isTrue(root.get("merchantability")));
                    }

                    //多门店
                    if(StringUtils.isNotBlank(storeIds)){
                        CriteriaBuilder.In<Long> in = cb.in(root.get("merchantId"));
                        for (String s : storeIds.split(",")) {
                            in.value(Long.valueOf(s));
                        }
                        predicates.add(in);
                    }else{
                        if(store != null){
                            predicates.add(cb.equal(root.get("merchantId"), store.getMerchantId()));
                        }
                    }

                    if(isDefault){
                        predicates.add(cb.isTrue(root.get("isDefault")));
                    }
                    predicates.add(cb.notEqual(root.get("itemType"), ProductSkuType.GIFTWRAP));

                    /** 分类名称筛选*/
                    if(StringUtils.isNotBlank(categoryName)){
                        List<Category> categories = categoryRepository.findAllByCategoryNameLike("%".concat(categoryName).concat("%"));
                        if(!categories.isEmpty()){
                            Join<ProductSku, Category> category = root.join("category", JoinType.INNER);
                            ArrayList<Predicate> predicateList = Lists.newArrayList();
                            categories.forEach(category1 -> {
                                String concat = "%/".concat(category1.getCategoryId() + "").concat("%");
                                predicateList.add(cb.like(category.get("categoryLineage"), concat));
                            });
                            predicates.add(cb.or(predicateList.toArray(new Predicate[categories.size()])));
                        }
                    }
                    /** 品牌名称筛选*/
                    if(StringUtils.isNotBlank(brandName)){
                        Join<Product, ProductBrand> brand = product.join("productBrand", JoinType.INNER);
                        predicates.add(cb.like(brand.get("brandName"),"%".concat(brandName).concat("%")));
                    }
                    /***
                     * SAP编码筛选
                     */
                    if (!StringUtils.isEmpty(externalIds)) {
                        ServiceUtils.findByExternalIds(predicates,root,cb,externalIds,false);
                    }
                    /**
                     * 商品名称筛选
                     */
                    if (!StringUtils.isEmpty(querykey)) {
                        predicates.add(cb.or(cb.like(root.get("skuName"), "%" + querykey + "%"),cb.like(root.get("keyword"), "%" + querykey + "%")));
                    }

                    if (!StringUtils.isEmpty(minPrice) && StringUtils.isEmpty(maxPrice)) {
                        predicates.add(cb.greaterThanOrEqualTo(root.get("salePrice"), new BigDecimal(minPrice)));
                    }
                    if (!StringUtils.isEmpty(maxPrice) && StringUtils.isEmpty(minPrice)) {
                        predicates.add(cb.lessThanOrEqualTo(root.get("salePrice"), new BigDecimal(maxPrice)));
                    }
                    if (!StringUtils.isEmpty(minPrice) && !StringUtils.isEmpty(maxPrice) && new BigDecimal(minPrice).compareTo(new BigDecimal(maxPrice)) < 0) {
                        predicates.add(cb.between(root.get("salePrice"), new BigDecimal(minPrice), new BigDecimal(maxPrice)));
                    }

                    if (!StringUtils.isEmpty(brandIds)) {
                        String[] brands = brandIds.split(",");
                        CriteriaBuilder.In<Long> in = cb.in(root.get("productBrandId"));
                        for (String brandId : brands) {
                            in.value(Long.parseLong(brandId));
                        }
                        predicates.add(in);
                    }
                    Predicate[] p = new Predicate[predicates.size()];
                    return cb.and(predicates.toArray(p));
            }
        };
    }

    @Override
    public PageVO findAllPage(MerchantStore store,String storeIds , String externalIds ,  String categoryName, String brandName, Integer page, Integer size, String sortOrder, String minPrice, String maxPrice, String key, String brandId, String available , Boolean isDefault) {

        Page<ProductSku> resultSkus = getProductsByStore(store,storeIds,externalIds, categoryName, brandName, page, size, sortOrder, minPrice, maxPrice, key, brandId, available , isDefault,false,false);
        Assert.notEmpty(resultSkus.getContent(),"没有数据");

        List showSkus = new ArrayList();
        Long totalElements = resultSkus.getTotalElements();
        PageVO pageVO = new PageVO(page, size, totalElements.intValue(), showSkus);

        resultSkus.getContent().stream().forEach((ProductSku productSku) -> {
            Product product = productSku.getProduct();
            Map defaultSkuMap = resultSkuModel(productSku);
            defaultSkuMap.put("productId", product.getProductId());
            defaultSkuMap.put("brandName", product.getProductBrand().getBrandName());
            defaultSkuMap.put("categoryName", product.getProductCategory().getCategoryName());
            defaultSkuMap.put("externalId", product.getExternalId());

            // sku数据填充
            List<Map> skus = new ArrayList<>();
            defaultSkuMap.put("skus", skus);
            product.getProductSkus().stream().forEach((ProductSku sku) -> {
                if (!Boolean.TRUE.equals(sku.isDefault())) {
                    Map skuModel = resultSkuModel(sku);
                    //Map<String, String> optionMap = new HashMap<>();
                    //ArrayList<Map> options = new ArrayList<>();
                    /*ArrayList<String> options = new ArrayList<>();
                    skuModel.put("options", options);
                    //  规格数据填充
                    List<SkuOptionValue> skuOptionValues = sku.getSkuOptionValues();
                    skuOptionValues.stream().forEach((SkuOptionValue skuOptionValue) -> {

                        ProductOptionValue productOptionValue = skuOptionValue.getProductOptionValue();
                        String optionValueName = productOptionValue.getAttributeValue();
                        String optionName = productOptionValue.getProductOption().getAttributeName();
                        //optionMap.put(optionName, optionValueName);
                        //options.add(optionMap);
                        options.add(optionValueName);
                    });*/

                    skus.add(skuModel);
                }
            });
            // 计算所有sku库存数量
            defaultSkuMap.put("stock", skus.stream().mapToInt(map -> (int)map.get("stock")).sum());
            ProductSku defaultSku = product.getDefaultSku();
            if(defaultSku.getMerchantability()){
                defaultSkuMap.put("stock", defaultSku.getQuantityAvailable());
            }
            showSkus.add(defaultSkuMap);
        });

        return pageVO;

    }

    private Map resultSkuModel(ProductSku productSku) {
        Map defaultSkuMap = new HashMap<>(6);
        defaultSkuMap.put("skuId",productSku.getSkuId());
        defaultSkuMap.put("skuName",productSku.getSkuName());
        defaultSkuMap.put("skuCost",productSku.getSkuCost());
        defaultSkuMap.put("specification",productSku.getUnit());
        defaultSkuMap.put("skuSalePrice",productSku.getSalePrice());
        Boolean available = productSku.getAvailable();
        defaultSkuMap.put("available",available==null?Boolean.TRUE:available);
        Integer stock = productSku.getQuantityAvailable();
        defaultSkuMap.put("stock",stock==null?0:stock);
        defaultSkuMap.put("storeCode",storeService.getMerchantStore(productSku.getMerchantId()).getStoreCode());
        defaultSkuMap.put("storeId",storeService.getMerchantStore(productSku.getMerchantId()).getMerchantId());
        defaultSkuMap.put("productId",productSku.getProduct().getProductId());
        return defaultSkuMap;
    }

    /**
     * 保存商品数据
     *
     * @param productAddModel 商品数据:{ sku数组+ product基本信息 + 门店}
     * @param store
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void newProduct(User user ,ProductAddModel productAddModel, MerchantStore store) {

        verifyQualified(productAddModel,store);

        ProductBasicModel productBasicModel = productAddModel.getProductBasicModel();
        List<ProductSkuModel> skuModels = productAddModel.getSkuModels();

        //保存商品信息
        Product product = new Product();
        BeanUtils.copyProperties(productBasicModel, product);
        product = productRepository.save(product = setRelatedProductInfo(user,productBasicModel,product,store));

        /**保存默认商品信息*/
        ProductSku defaultSku = setDefaultSku(user,product,productBasicModel);
        defaultSku.setCreatedTimestamp(new Date());
        defaultSku.setMerchantId(store.getMerchantId());
        product.setDefaultSku(defaultSku = productSkuRepository.save(defaultSku));

        //新增默认sku排序图片
        newDefaultSkuMedia(productBasicModel, defaultSku);
        if(CollectionUtils.isEmpty(skuModels)){
            // 没有sku  设置默认sku可售
            defaultSku.setMerchantability(Boolean.TRUE);
            return;
        }

        /**保存sku + 规格图片*/
        Map<Long, List<ProductOption>> listMap = productOptionRepository.findAll().stream().collect(Collectors.groupingBy(o -> o.getProductOptionId()));
        for (ProductSkuModel skuModel : skuModels) {
            //新建sku
            ProductSku sku = newProductSku(user,product,productBasicModel,skuModel);
            // 新建图片与规格信息
            newMediaAndOption(listMap, skuModel, sku);
        }
    }

    private void verifyQualified(ProductAddModel productAddModel, MerchantStore store) {
        Assert.notNull(store,"门店不能为空");
        /*String externalId = productAddModel.getProductBasicModel().getExternalId();
        if(sapStoreGoodsRepository.findFirstByMatnrAndLocnr(externalId, store.getExternalId())==null){
            Assert.notNull(sapStoreProductRepository.findFirstByMatnrAndLocnr(externalId,store.getExternalId()),"门店没有绑定该商品数据");
        }*/

        ProductBasicModel model = productAddModel.getProductBasicModel();
        SapContractProduct contractProduct = sapContractProductService.verifyContract(model.getExternalId(), store.getExternalId(), model.getActiveEndDate());

        sapContractService.verifyContract(contractProduct,model.getActiveEndDate());
    }

    /**
     * 修改商品数据
     *
     * @param productAddModel 商品数据:{ sku数组+ product基本信息}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void mergeProduct(User user ,ProductAddModel productAddModel) {

        ProductBasicModel productBasicModel = productAddModel.getProductBasicModel();
        List<ProductSkuModel> skuModels = productAddModel.getSkuModels();

        /** 校验数据*/
        Long productId = productBasicModel.getProductId();
        Assert.notNull(productId,"商品Id不能为空");
        Product product = productRepository.findOne(productId);
        Assert.notNull(product,"该商品不存在");
        Assert.isTrue(!product.isAvailable(),"下架商品才能修改");

        /** 主商品校验成功 先设置主商品数据*/
        setProduct(user,productBasicModel,product);
        product = productRepository.save(product);
        // 保存商品价格变更历史记录
        ProductSku defaultSku = product.getDefaultSku();
        ProductService service = (ProductServiceImpl) AopContext.currentProxy();
        //保存商品价格修改历史记录
        service.savePriceHistory(user,defaultSku,productBasicModel.getRetailPrice(),productBasicModel.getRetailPrice());
        /** 修改默认商品*/
        defaultSku = setDefaultSku(user,product, productBasicModel);
        defaultSku = productSkuRepository.save(defaultSku);

        // DEFAULT商品 图文描述修改: 删除之前所有图片重新添加; 因为排序所有数据都得走一次更新 java校验并不能优化数据库操作,所以直接删除 目前没找到更好解决办法;
        //newDefaultSkuMedia(productBasicModel,defaultSku);

        List<ProductSku> productSkus = product.getProductSkus();
        /** 修改的商品 没有sku*/
        if(CollectionUtils.isEmpty(skuModels)){
            /** 修改的商品之前存在sku   删除之前sku (不包含默认sku)*/
            if(CollectionUtils.isNotEmpty(productSkus)){
                List<ProductSku> skus = productSkus.stream().filter(sku -> {
                    return !Boolean.TRUE.equals(sku.isDefault());
                }).collect(Collectors.toList());
                //删除sku 绑定的图片
                skus.stream().forEach(sku -> {
                    skuMediaMapRepository.delete(sku.getSkuMediaMaps());
                    //删除sku 绑定规格
                    skuOptionValueRepository.delete(sku.getSkuOptionValues());
                });
                //删除sku
                productSkuRepository.delete(skus);
            }
            return;
        }

        /** 校验传递的skuId 正确性*/
        verifySku(productSkus,skuModels);

        //得到所有规格Option        -- 修改规格会进行比较
        Map<Long, List<ProductOption>> listMap = productOptionRepository.findAll().stream().collect(Collectors.groupingBy(ProductOption::getProductOptionId));
        // 修改商品SKU 数据
        Map<Long, List<ProductSku>> skuMaps = productSkus.stream().collect(Collectors.groupingBy(ProductSku::getSkuId));
        for (ProductSkuModel skuModel : skuModels) {

            // 需要新增的sku
            if(skuModel.getSkuId()==null){
                ProductSku sku = newProductSku(user,product,productBasicModel,skuModel);
                newMediaAndOption(listMap, skuModel, sku);
            }else{

                // 修改已存在的sku
                ProductSku sku = skuMaps.get(skuModel.getSkuId()).get(0);
                Assert.notNull(sku,String.format("该sku不存在: %s , 检查是否已经删除..",skuModel.getSkuId()));
                // 保存商品价格变更历史记录
                service.savePriceHistory(user,sku,skuModel.getSalePrice(),productBasicModel.getRetailPrice());
                BeanUtils.copyProperties(productBasicModel,sku);
                BeanUtils.copyProperties(skuModel, sku);
                if(productBasicModel.getSkuShipmentId()!=null){
                    sku.setShipmentTemplate(skuShipmentRepository.findOne(productBasicModel.getSkuShipmentId()));
                }
                sku.setCategory(product.getProductCategory());
                sku.setProductBrandId(product.getProductBrand().getProductBrandId());
                sku.setUpdatedTimestamp(new Date());
                sku.setSkuName(joiningTogetherSkuName(product,skuModel.getOptionModels()));
                sku.setUpdatedBy(user.getAdminName());
                sku = productSkuRepository.save(sku);

                // 修改图片
                updateMediaAndOption(sku,skuModel,listMap);
            }
        }
    }


    @Async
    @Override
    public void savePriceHistory(User user , ProductSku sku , BigDecimal skuPrice ,BigDecimal retailPrice) {
        SkuPriceHistory priceHistory=new SkuPriceHistory();
        //ProductSku sku = productSkuService.getSkuById(skuId);
        try {
            if (sku.getSalePrice().compareTo(skuPrice) != 0) {
                priceHistory.setRetailPrice(retailPrice);
                priceHistory.setRecentRetialPrice(sku.getRetailPrice());
                priceHistory.setSkuPrice(skuPrice);
                priceHistory.setRecentPrice(sku.getSalePrice());
                priceHistory.setUpdatedTimestamp(new Date());
                priceHistory.setCreatedTimestamp(new Date());
                priceHistory.setUpdatedBy(user.getAdminName());
                priceHistory.setProductSku(sku);
                priceHistory.setSkuDescription(sku.getSkuDescription());
                if (priceHistoryRepository.save(priceHistory) == null) {
                    log.error("sku价格历史记录保存失败..", priceHistory.toString());
                }
            }
        } catch (Exception e) {
            log.error(String.format("sku价格历史记录保存失败.. %s",priceHistory.toString()), e);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PageVO skuDetailList(MerchantStore merchantStore, String storeIds, String externalIds, String categoryName, String brandName, Integer page, Integer pageSize, String sortOrder, String minPrice, String maxPrice, String skuName, String brandId, String available) {
        Page<ProductSku> resultSkus = getProductsByStore(merchantStore,storeIds,externalIds, categoryName, brandName, page, pageSize, sortOrder, minPrice, maxPrice, skuName, brandId, available , false,true,true);
        Assert.notEmpty(resultSkus.getContent(),"没有数据");
        List showSkus = new ArrayList();
        Long totalElements = resultSkus.getTotalElements();
        PageVO pageVO = new PageVO(page, pageSize, totalElements.intValue(), showSkus);
        for(ProductSku productSku : resultSkus){
            SkuExcelModel skuExcelModel = transSkuToExcelModel(productSku);
            showSkus.add(skuExcelModel);
        }
        return pageVO;
    }

    private SkuExcelModel transSkuToExcelModel(ProductSku productSku) {
        SkuExcelModel skuExcelModel = new SkuExcelModel();
        skuExcelModel.setSkuId(productSku.getSkuId());
        skuExcelModel.setExternalId(productSku.getExternalId());
        skuExcelModel.setSkuName(productSku.getSkuName());
        StringBuffer specification = new StringBuffer();
        if(StringUtils.isNotEmpty(productSku.getSkuDescription())){
            String[] descriptions = productSku.getSkuName().split(" ");
            for(int i = 1;i < descriptions.length ; i++){
                specification.append(descriptions[i]).append(" ");
            }
        }
        skuExcelModel.setSpecification(specification.toString().trim());
        ProductBrand productBrand = brandRepository.findOne(productSku.getProductBrandId());
        skuExcelModel.setBrandName("["+productBrand.getProductBrandId()+"]"+productBrand.getBrandName());
        skuExcelModel.setCategoryName("["+productSku.getProduct().getExternalCcategory()+"]"+productSku.getCategory().getCategoryName());
        skuExcelModel.setAvailable(productSku.getProduct().isAvailable() ? "上架" : "下架");
        skuExcelModel.setStock(String.valueOf(productSku.getQuantityAvailable() == null ? 0 : productSku.getQuantityAvailable()));
        return skuExcelModel;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<SkuExcelModel> skuDetail(MerchantStore merchantStore, String storeIds, String externalIds, String categoryName, String brandName, String minPrice, String maxPrice, String skuName, String brandId, String available) {
        Specification<ProductSku> query = createSkuSpecification(merchantStore,storeIds,externalIds, categoryName, brandName, minPrice, maxPrice, skuName, brandId,available, false,true,true);
        List<ProductSku> productSkus =  productSkuRepository.findAll(query);
        List<SkuExcelModel> skuExcelModels = Lists.newArrayList();
        int index = 0;
        for(ProductSku productSku : productSkus){
            SkuExcelModel skuExcelModel = transSkuToExcelModel(productSku);
            skuExcelModel.setIndex( ++index );
            skuExcelModels.add(skuExcelModel);
        }
        return skuExcelModels;
    }

    private void updateMediaAndOption(ProductSku sku, ProductSkuModel skuModel, Map<Long, List<ProductOption>> listMap) {
        updateMedias(sku,skuModel);
        updateOptions(sku,skuModel,listMap);
    }

    private void updateOptions(ProductSku sku, ProductSkuModel skuModel, Map<Long, List<ProductOption>> listMap) {

        // 修改规格
        List<SkuOptionValue> skuOptionValues = sku.getSkuOptionValues();
        List<OptionModel> optionModels = skuModel.getOptionModels();
        //  上传的规格为空  数据库规格不为空
        if (CollectionUtils.isEmpty(optionModels) && CollectionUtils.isNotEmpty(skuOptionValues)) {

            sku.setSkuOptionValues(null);
            sku.setLongDescription(null);
            productSkuRepository.save(sku);
        } else if (optionModels != null) {

            // optionXrefId 不为NULL 认为含有之前规格 进行比较  新上传规格不包含之前规格  删除规格

            List<Long> notNullOption = optionModels.stream().filter(optionModel -> {
                return optionModel.getOptionXrefId() != null;
            }).map(OptionModel::getOptionXrefId).collect(Collectors.toList());

            /*skuOptionValueRepository.deleteNotExistOption(sku.getSkuId(),notNullOption);
             编程式删除  尽量不用 not in
             */

            //得到sku的 description
            List<String> skuDescriptions = skuOptionValues.stream().map(skuOptionValue -> {
                return skuOptionValue.getProductOptionValue().getProductOptionValueId()+"";
            }).collect(Collectors.toList());
            List<String> removeSkuDescriptions=Lists.newArrayList();

            //删除option
            skuOptionValues.forEach(skuOptionValue -> {
                Long optionValueXrefId = skuOptionValue.getSkuOptionValueXrefId();
                if (!notNullOption.contains(optionValueXrefId)) {
                    removeSkuDescriptions.add(skuOptionValue.getProductOptionValue().getProductOptionValueId()+"");
                    skuOptionValueRepository.delete(optionValueXrefId);
                }
            });

            skuDescriptions.removeAll(removeSkuDescriptions);

            // optionXrefId 为NULL 认为是新增规格
            optionModels.stream().filter(optionModel -> {
                return optionModel.getOptionXrefId() == null;
            }).forEach(optionModel -> {
                skuDescriptions.add(addOptionModels(sku, listMap, optionModel));
            });
            sku.setSkuDescription(String.join(",",skuDescriptions));
            productSkuRepository.save(sku);
        }
    }

    private void updateMedias(ProductSku sku, ProductSkuModel skuModel) {

        List<SkuMediaMap> skuMedias = sku.getSkuMediaMaps();
        List<MediaModel> mediaList = skuModel.getMediaList();
        if(CollectionUtils.isEmpty(mediaList)){
            if(CollectionUtils.isNotEmpty(skuMedias)){
                sku.setSkuMediaMaps(null);
            }
        }else {
            List<Long> mediaModels= mediaList.stream()
                    .filter(mediaModel -> {return mediaModel.getSkuMediaId()!=null;})
                    .map(MediaModel::getSkuMediaId).collect(Collectors.toList());
            if(CollectionUtils.isNotEmpty(skuMedias)){
                // 如果在上传图片中不包含数据库图片hash 解除与之前图片的关系
                skuMedias.stream().forEach(skuMediaMap -> {
                    if (!mediaModels.contains(skuMediaMap.getSkuMediaId())) {
                        skuMediaMapRepository.delete(skuMediaMap.getSkuMediaId());
                    }
                });
            }
            // skuMediaId 为NULL 被认为新增图片
            mediaList.stream().filter(mediaModel -> {
                return mediaModel.getSkuMediaId() == null;
            }).forEach(mediaModel -> {
                addSkuMedia(sku, mediaModel);
            });
        }
    }

    /**
     * 获取当前门店所有未上架的商品
     *
     * @param merchantId
     * @param externalIds
     * @param productName
     * @param enableUpload
     * @param auditStatus
     * @param startTime
     * @param endTime
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public PageVO getInitCommodityProduct(Long merchantId,String storeIds , String externalIds, String productName, String enableUpload, String auditStatus, String startTime,String endTime,Integer page, Integer pageSize) {
        Pageable pageable=new PageRequest(page -1,pageSize,new Sort(Sort.Direction.DESC,"updatedTimestamp"));
        Specification<Product> query=new Specification<Product>() {
            @Override
            public Predicate toPredicate(Root<Product> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
                List<Predicate> predicates=new ArrayList<>();
                // 获取下架商品
                predicates.add(cb.isFalse(root.get("available")));
                //判断商品是否软删除
                predicates.add(cb.or(cb.isNull(root.get("archived")),cb.isFalse(root.get("archived"))));
                //默认sku
                Join<Product,ProductSku> productSku=root.join("defaultSku",JoinType.INNER);
                Path<Boolean> isDefault=productSku.get("isDefault");
                predicates.add(cb.isTrue(isDefault));
                //增加条件门店
                //多门店
                if(StringUtils.isNotBlank(storeIds)){
                    CriteriaBuilder.In<Long> in = cb.in(root.get("merchantId"));
                    for (String s : storeIds.split(",")) {
                        in.value(Long.valueOf(s));
                    }
                    predicates.add(in);
                }else{
                    if(merchantId != null){
                        predicates.add(cb.equal(root.get("merchantId"), merchantId));
                    }
                }
                if (StringUtils.isNotBlank(externalIds)){
                    String[] exterIds=externalIds.split(",");
                    CriteriaBuilder.In<String> in=cb.in(root.get("externalId"));
                    for (int i=0;i<exterIds.length;i++){
                        in.value(exterIds[i]);
                    }
                    predicates.add(in);
                }
                if (StringUtils.isNotBlank(productName)){
                    predicates.add(cb.like(root.get("productName"),"%"+productName+"%"));
                }
                if (StringUtils.isNotBlank(enableUpload)){
                    Path<Boolean> enable=productSku.get("enableUpload");
                    Boolean isEnableUpload=Boolean.valueOf(enableUpload);
                    if (isEnableUpload){
                        predicates.add(cb.equal(enable,isEnableUpload));
                    }else{
                        predicates.add(cb.or((cb.isNull(enable)),cb.isFalse(enable)));
                    }
                }
                if (StringUtils.isNotBlank(auditStatus)){
                    String[] audits=auditStatus.split(",");
                    CriteriaBuilder.In<String> in=cb.in(root.get("auditStatus"));
                    Arrays.stream(audits).forEach(a->{
                        in.value(a);
                    });
                    predicates.add(in);
                }else {
                    predicates.add(cb.or(cb.equal(root.get("auditStatus"),"READY_FOR_SALE"),cb.equal(root.get("auditStatus"),"REJECT_SALE_AUDITING")));
                }
                if (StringUtils.isNotBlank(startTime)){
                    predicates.add(cb.greaterThanOrEqualTo(root.get("updatedTimestamp"), DateUtils.parse(startTime,DateUtils.DEFAULT_DATE_FORMAT)));
                }
                if (StringUtils.isNotBlank(endTime)){
                    predicates.add(cb.lessThanOrEqualTo(root.get("updatedTimestamp"), DateUtils.parse(endTime,DateUtils.DEFAULT_DATE_FORMAT)));
                }
                Predicate[] p=new Predicate[predicates.size()];
                return cb.and(predicates.toArray(p));
            }
        };
        Page data=productRepository.findAll(query,pageable);
        if (data!=null&&data.hasContent()){
            List<Product> products=data.getContent();
            List<ProductVO> productVOS= Lists.newArrayListWithExpectedSize(products.size());
            //把数据转换到ProductVO中
            products.stream().forEach(product -> {
                productVOS.add(convertProductVO(product));
            });
            return new PageVO(data.getNumber(),data.getSize(),(int)data.getTotalElements(),productVOS);
        }
        return null;
    }

    /**
     * 获取所有商品的审核状态
     *
     * @param merchantId
     * @param externalIds
     * @param productName
     * @param auditStatus
     * @param startTime
     * @param endTime
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public PageVO getAuditCommodityProduct(Long merchantId,String storeIds, String externalIds, String productName, String auditStatus, String startTime, String endTime, Integer page, Integer pageSize) {
        Pageable pageable=new PageRequest(page -1,pageSize,new Sort(Sort.Direction.DESC,"updatedTimestamp"));
        Specification<Product> query=new Specification<Product>() {
            @Override
            public Predicate toPredicate(Root<Product> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
                List<Predicate> predicates=new ArrayList<>();
                //判断商品是否软删除
                predicates.add(cb.or(cb.isNull(root.get("archived")),cb.isFalse(root.get("archived"))));
                //默认sku
                Join<Product,ProductSku> productSku=root.join("defaultSku",JoinType.INNER);
                Path<Boolean> isDefault=productSku.get("isDefault");
                predicates.add(cb.isTrue(isDefault));
                //多门店
                if(StringUtils.isNotBlank(storeIds)){
                    CriteriaBuilder.In<Long> in = cb.in(root.get("merchantId"));
                    for (String s : storeIds.split(",")) {
                        in.value(Long.valueOf(s));
                    }
                    predicates.add(in);
                }else{
                    if(merchantId != null){
                        predicates.add(cb.equal(root.get("merchantId"), merchantId));
                    }
                }
                if (StringUtils.isNotBlank(externalIds)){
                    String[] exterIds=externalIds.split(",");
                    CriteriaBuilder.In<String> in=cb.in(root.get("externalId"));
                    for (int i=0;i<exterIds.length;i++){
                        in.value(exterIds[i]);
                    }
                    predicates.add(in);
                }
                if (StringUtils.isNotBlank(productName)){
                    predicates.add(cb.like(root.get("productName"),"%"+productName+"%"));
                }
                if (StringUtils.isNotBlank(auditStatus)){
                    predicates.add(cb.equal(root.get("auditStatus"),auditStatus));
                }else {
                    predicates.add(cb.equal(root.get("auditStatus"),"ON_SALE_AUDITING"));
                }

                // 2018/7/31  @Lee
                if(auditStatus.equalsIgnoreCase("ON_SALE")){
                    //获取上架（审核完成）商品
                    predicates.add(cb.isTrue(root.get("available")));
                }else {
                    //获取下架（未审）商品
                    predicates.add(cb.isFalse(root.get("available")));
                }

                if (StringUtils.isNotBlank(startTime)){
                    predicates.add(cb.greaterThanOrEqualTo(root.get("updatedTimestamp"), DateUtils.parse(startTime,DateUtils.DEFAULT_DATE_FORMAT)));
                }
                if (StringUtils.isNotBlank(endTime)){
                    predicates.add(cb.lessThanOrEqualTo(root.get("updatedTimestamp"), DateUtils.parse(endTime,DateUtils.DEFAULT_DATE_FORMAT)));
                }
                Predicate[] p=new Predicate[predicates.size()];
                return cb.and(predicates.toArray(p));
            }
        };
        Page data=productRepository.findAll(query,pageable);
        if (data!=null&&data.hasContent()){
            List<Product> products=data.getContent();
            List<ProductVO> productVOS=Lists.newArrayListWithExpectedSize(products.size());
            //把数据转换到ProductVO中
            products.stream().forEach(product -> {
                productVOS.add(convertProductVO(product));
            });
            return new PageVO(data.getNumber(),data.getSize(),(int)data.getTotalElements(),productVOS);
        }
        return null;
    }

    /**
     * 审核商品
     *
     * @param ids
     * @param auditStatus
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String auditCommodityProduct(String ids, String auditStatus) {
        if (StringUtils.isNotBlank(ids)){
            String[] productIds=ids.split(",");
            ArrayList<Long> pids=new ArrayList<>(productIds.length);
            try {
                Arrays.stream(productIds).forEach(p->{
                    pids.add(Long.valueOf(p));
                });
            } catch (Exception e) {
                e.printStackTrace();
                log.error("类型转换失败");
            }
            switch (auditStatus){
                case "ON_SALE_AUDITING":
                    productRepository.updateProduct(pids,auditStatus,new Date(),false);
                    return "ok";
                case "ON_SALE":
                    productRepository.updateProduct(pids,auditStatus,new Date(),true);
                    return "ok";
                case "REJECT_SALE_AUDITING":
                    productRepository.updateProduct(pids,auditStatus,new Date(),false);
                    return "ok";
                case "SOLD_OUT_AUDTING":
                    productRepository.updateProduct(pids,"READY_FOR_SALE",new Date(),false);
                    return "ok";
                default:
                    break;
            }
        }
        return "error";
    }

    /**
     * 保存并提交
     *
     * @param userId
     * @param imgUploadVOs
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void keepAndSubmit(Long userId, List<ProductImgUploadRO> imgUploadVOs) throws IOException {
        User user=null;
        if (userId!=null){
            user=adminUserRepository.findOne(userId);
        }
        upload(user, imgUploadVOs);
        imgUploadVOs.stream().forEach(product->{
            if (product.getProductId()!=null){
                List<Long> pids=new ArrayList<>(1);
                pids.add(product.getProductId());
                productRepository.updateProduct(pids,"ON_SALE_AUDITING",new Date(),false);
            }

        });
    }

    /**
     * 商品上下热门
     *
     * @param productIds
     * @param featuredProduct
     */
    @Override
    public void upOrDownHot(String productIds, Boolean featuredProduct) {
        Asserts.notBlank(productIds,"商品编号不能为空");
        try {
            String[] products=productIds.split(",");
            List<Long> pids=new ArrayList<>(products.length);
            Arrays.stream(products).forEach(product->{
                pids.add(Long.parseLong(product));
            });
            productRepository.batchUpdateFeature(pids,featuredProduct,new Date());
        } catch (Exception e) {
            e.printStackTrace();
            log.error("类型转换失败");
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ProductAddModel sapGoodsDetail(MerchantStore store , String externalId) {

        SapGoods goods = sapGoodsRepository.findFirstByMatnr(externalId);
        SapProduct sapProduct=null;
        if(goods==null){
            sapProduct = sapProductRepository.findFirstByMatnr(externalId);
        }
        ProductAddModel productAddModel = new ProductAddModel();
        productAddModel.setProductBasicModel(newProductBasicModel(goods,sapProduct));
        return productAddModel;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchKeyWordImport(User user, Long storeId ,KeywordBatchRO keywordBatchRO) {

        for (KeywordRO keywordRO : keywordBatchRO.getKeywordROS()) {
            // 批量导入
            if(keywordBatchRO.getBatchImport()){
                List<ProductSku> skus;
                // 多门店
                if(StringUtils.isNotBlank(keywordBatchRO.getStoreIds())){
                    Assert.notEmpty(skus = productSkuRepository.findAllByExternalIdAndMerchantIdIn(keywordRO.getExternalId(),
                            Arrays.stream(keywordBatchRO.getStoreIds().split(",")).map(s ->
                            {return Long.valueOf(s);}).collect(Collectors.toList())),String.format("商品不存在 编码: %s", keywordRO.getExternalId()));
                }else {
                    // 单门店
                    Assert.notEmpty(skus = productSkuRepository.findAllByExternalIdAndMerchantId(keywordRO.getExternalId(),storeId),String.format("商品不存在 编码: %s", keywordRO.getExternalId()));
                }
                for (ProductSku sku : skus) {
                    sku.setKeyword(keywordRO.getKeyWord());
                    sku.setUpdatedBy(user.getAdminName());
                    sku.setUpdatedTimestamp(new Date());
                }
                // 批量修改
            }else {
                ProductSku sku;
                Assert.notNull(sku = productSkuRepository.findOne(keywordRO.getSkuId()),String.format("商品不存在 SkuId: %s", keywordRO.getSkuId()));
                sku.setKeyword(keywordRO.getKeyWord());
                sku.setUpdatedBy(user.getAdminName());
                sku.setUpdatedTimestamp(new Date());
            }
        }
    }

    @Override
    public PageVO findSkuByKeyWord(String externalIds, Long storeId,String storeIds,String queryKey, Integer page, Integer pageSize) {
        Page<ProductSku> skus = getProductsByStore(storeService.getMerchantStore(storeId), storeIds, externalIds, "", "",page, pageSize, "", "", "", queryKey, "", "", true,false,false);

        Assert.notEmpty(skus.getContent(),"没有数据");
        ArrayList<Map> keyWords = Lists.newArrayList();
        skus.getContent().forEach(sku -> {
            keyWords.add(TransformUtils.transformToSkuKeyWord(sku));
        });

        return new PageVO<>(page,pageSize,(int)skus.getTotalElements(),keyWords);
    }

    private ProductBasicModel newProductBasicModel(SapGoods goods , SapProduct sapProduct) {

        ProductBasicModel model = new ProductBasicModel();
        model.setBrandId(Long.valueOf(goods==null?sapProduct.getZzppbm():goods.getZzppbm()));
        model.setExternalCcategory(goods==null?sapProduct.getMatkl():goods.getMatkl());
        model.setModel(goods==null?sapProduct.getMaktm():goods.getMaktm());
        model.setUnit(goods==null?sapProduct.getMeins():goods.getMeins());
        model.setOriginPlace(goods==null?sapProduct.getZzcd():goods.getZzcd());
        model.setExternalId(goods==null?sapProduct.getMatnr():goods.getMatnr());
        model.setProductName(goods==null?sapProduct.getMaktx():goods.getMaktx());
        return model;
    }

    /**
     * product转换成productVO
     */
    private ProductVO convertProductVO(Product product){
        List<SkuMediaMap> skuMediaMaps=product.getDefaultSku().getSkuMediaMaps();
        List<ImgVo> imgheader=Lists.newArrayListWithExpectedSize(skuMediaMaps.size());
        List<ImgVo> imgdetail=Lists.newArrayListWithExpectedSize(skuMediaMaps.size());
        skuMediaMaps.stream().forEach(skuMediaMap -> {
            if (skuMediaMap.getMapKey().contains("PRIMARY")){
                ImgVo imgVo=new ImgVo();
                if (skuMediaMap.getMedia()!=null){
                    if (StringUtils.isNotBlank(skuMediaMap.getMedia().getUrl())){
                        imgVo.setUrl(HttpRequestUtils.getUrl(skuMediaMap.getMedia().getUrl()));
                    }
                    imgheader.add(imgVo);
                }
            }else if (skuMediaMap.getMapKey().contains("DESCRIPTION")){
                ImgVo imgVo=new ImgVo();
                if (skuMediaMap.getMedia()!=null){
                    if (StringUtils.isNotBlank(skuMediaMap.getMedia().getUrl())){
                        imgVo.setUrl(HttpRequestUtils.getUrl(skuMediaMap.getMedia().getUrl()));
                    }
                    imgdetail.add(imgVo);
                }
            }
        });
        return ProductVO.builder()
                .productId(product.getProductId())
                .productName(product.getProductName())
                .productBrandName(product.getProductBrand().getBrandName())
                .productCategoryName(product.getProductCategory().getCategoryName())
                .productExternalId(product.getExternalId())
                .auditStatus(product.getAuditStatus())
                .defaultSkuId(product.getDefaultSku().getSkuId())
                .skuCode(product.getDefaultSku().getSkuCode())
                .skuName(product.getDefaultSku().getSkuName())
                .skuExternalId(product.getDefaultSku().getExternalId())
                .skuImgheader(imgheader)
                .skuImgdetail(imgdetail)
                .skuSalePrice(product.getDefaultSku().getSalePrice())
                .enableUpload(product.getDefaultSku().getEnableUpload()==null?false:product.getDefaultSku().getEnableUpload())
                .hot(product.getFeaturedProduct())
                .updatedTimestamp(product.getUpdatedTimestamp()).build();
    }

    private void verifySku(List<ProductSku> productSkus, List<ProductSkuModel> skuModels) {

        List<Long> skuIds = productSkus.stream().filter(sku -> {return !Boolean.TRUE.equals(sku.isDefault());}).map(ProductSku::getSkuId).collect(Collectors.toList());

        for (ProductSkuModel skuModel : skuModels) {
            if (skuModel.getSkuId()!=null&&!skuIds.contains(skuModel.getSkuId())) {
                throw new KnownRuntimeException("不存在商品: %s ", skuModel.getSkuName());
            }
        }

        /** 可能存在删除已有sku商品  删除sku(不包括默认sku)*/
        List<Long> modelSkuIds = skuModels.stream().filter(skuModel -> {
            return skuModel.getSkuId() != null;
        }).map(ProductSkuModel::getSkuId).collect(Collectors.toList());

        skuIds.forEach(skuId -> {
            if(!modelSkuIds.contains(skuId)){
                productSkuRepository.delete(skuId);
            }
        });
    }

    private void setProduct(User user ,ProductBasicModel productBasicModel, Product product) {
        BeanUtils.copyProperties(productBasicModel, product);
        Category category = categoryRepository.findOne(productBasicModel.getCategoryId());
        ProductBrand brand = brandRepository.findOne(productBasicModel.getBrandId());
        product.setProductCategory(category);
        product.setProductBrand(brand);
        product.setUpdatedTimestamp(new Date());
        product.setUpdatedBy(user.getAdminName());
    }

    /**
     * 查询展示商品数据
     *
     * @param productId 返回商品数据:{ sku数组+ product基本信息 + 门店}
     */
    @Override
    public ProductAddModel findProductModelById(Long productId) {

        Product product  = productRepository.findOne(productId);
        Assert.notNull(product,"商品不存在");
        ProductBasicModel basicModel = new ProductBasicModel();

        ArrayList<ProductSkuModel> skuModels = new ArrayList<>();
        ArrayList<com.bifrost.model.option.OptionModel> models = new ArrayList<>();
        ArrayList<Long> optionIds = new ArrayList<>();
        ArrayList<Long> optionValueIds = new ArrayList<>();
        product.getProductSkus().stream().forEach(sku -> {

            if (!Boolean.TRUE.equals(sku.isDefault())) {
                ProductSkuModel productSkuModel = new ProductSkuModel();
                BeanUtils.copyProperties(sku, productSkuModel);
                productSkuModel.setProductId(productId);
                // 设置规格展示
                productSkuModel.setOptionModels(resultOptionModel(optionIds,optionValueIds,models,sku));
                // 设置sku 图片Map
                productSkuModel.setMediaList(resultMediaModels(sku));
                skuModels.add(productSkuModel);
            }else{
                BeanUtils.copyProperties(sku,basicModel);
                BeanUtils.copyProperties(product, basicModel);
                basicModel.setDefaultAvaiable(sku.getAvailable());
                basicModel.setSkuShipmentId(sku.getShipmentTemplate()==null?null:sku.getShipmentTemplate().getSkuShipmentId());
                basicModel.setCategoryId(product.getProductCategory().getCategoryId());
                basicModel.setBrandId(product.getProductBrand().getProductBrandId());
                // 设置作用于前端拼装的 规格models

                basicModel.setMediaModels(resultMediaModels(sku));
            }

        });
        basicModel.setModels(models);
        return ProductAddModel.builder().productBasicModel(basicModel).skuModels(skuModels).build();

    }

    /**
     * @param user
     * @param imgUploadVOs 图片上传对象
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void upload(User user, List<ProductImgUploadRO> imgUploadVOs) throws IOException {


        for (ProductImgUploadRO uploadRO: imgUploadVOs) {
            /** 校验上传数据*/
            imgRoNotBlank(uploadRO);
            Product product;ProductSku sku;
            if(uploadRO.getProductId()!=null){
                product = productRepository.findOne(uploadRO.getProductId());
            }else {
                product = productRepository.findFirstByExternalId(uploadRO.getExternalId());
            }
            Assert.notNull(product,"商品不存在");
            Assert.notNull(sku = product.getDefaultSku(),"默认展示商品不存在");

            // 保存图片 删除之前所有图片数据 重新绑定
            imgToMeida(sku,uploadRO.getMainImgs(),  null,uploadRO.getTag(), null,"PRIMARY");
            imgToMeida(sku,uploadRO.getDetailImgs(), null, uploadRO.getTag(), null,"DESCRIPTION");
            sku.setUpdatedTimestamp(new Date());
            sku.setUpdatedBy(user.getAdminName());
            sku.setEnableUpload(Boolean.TRUE);

        }
    }

    private void imgToMeida(ProductSku sku , List<String> mainImgs, String title, @NotNull String tag, String altText , String key) {
        List<MultipartFile> mains = mainImgs.stream().map(src -> {
            return FileUploadUtils.stringToMultipartFile(src);
        }).collect(Collectors.toList());

        List<Media> medias = new ArrayList<>(mains.size());
        try {
            medias = mediaService.upload(mains.toArray(new MultipartFile[mains.size()]), title, tag, altText);
        } catch (FormatException e) {
            e.printStackTrace();
        }

        if(!medias.isEmpty()){
            // 拿到新上传图片
            mainImgs.addAll(medias.stream().map(Media::getUrl).collect(Collectors.toList()));
        }
        //拿到已有图片
        mainImgs.addAll(mainImgs.stream().filter(imgStr -> {
            return imgStr.startsWith("http://")||imgStr.startsWith("HTTP://");
        }).collect(Collectors.toList()));

        //删除所有数据 skuMediaMap  条件:{sku,key} 重新设置图片
        resetSkuMedias(mainImgs,sku,key);



    }

    private void resetSkuMedias(List<String> mainImgs, ProductSku sku, String key) {

        //删除所有图片
        skuMediaMapRepository.deleteAllByProductSkuAndMapKeyEquals(sku,key);
        //重新设置图片 保证不重复
        ArrayList<Media> medias = new ArrayList<>();
        mainImgs = mainImgs.stream().distinct().collect(Collectors.toList());
        for (String imgStr : mainImgs) {
            Media media = mediaRepository.findFirstByUrl(imgStr);
            if(media==null&&(imgStr.startsWith("http://")||imgStr.startsWith("HTTP://"))){
                media = mediaRepository.findFirstByUrl(imgStr.replaceFirst(HttpRequestUtils.getUrlAccessPath(),""));
            }
            if(media!=null){
                medias.add(media);
            }
        }
        // 保存瞬时状态的skuMediaMap
        for (Media media : medias) {
            SkuMediaMap mediaMap = new SkuMediaMap();
            mediaMap.setMedia(media);
            mediaMap.setMapKey(key);
            mediaMap.setProductSku(sku);
            mediaMap.setSortOrder(1);
            skuMediaMapRepository.save(mediaMap);
        }

        /*mainImgs.stream()
                .filter(s -> {return s.startsWith("http://")||s.startsWith("HTTP://"); }).forEach(s -> {
            Media media;
            if(s.startsWith(HttpRequestUtils.getUrlAccessPath())){
                media = mediaRepository.findFirstByUrl(s.replaceFirst(HttpRequestUtils.getUrlAccessPath(),""));
            }else {
                media  = mediaRepository.findFirstByUrl(s);
            }
            if(media!=null){
                medias.add(media.getMediaId());
            }
        });
        if(!medias.isEmpty()){skuMediaMapRepository.deleteMapNotIn(sku.getSkuId(),key,medias);}*/

    }

    /**
     *  根据key 得到sku的图片返回models
     * @param sku
     * @return
     */
    private List<MediaModel> resultMediaModels(ProductSku sku) {
        ArrayList<MediaModel> mediaModels = new ArrayList<>();
        List<SkuMediaMap> mediaMaps = sku.getSkuMediaMaps();
        mediaMaps.sort((o1, o2) -> {
            // 如果o1<o2 排在前面  --正序排序
            return o2.getSortOrder()-o1.getSortOrder();
        });

        mediaMaps.forEach(skuMediaMap -> {
            MediaModel mediaModel = new MediaModel();
            BeanUtils.copyProperties(skuMediaMap, mediaModel);
            setMedia(skuMediaMap, mediaModel);
            mediaModels.add(mediaModel);

        });
        return mediaModels;
    }

    private void setMedia(SkuMediaMap skuMediaMap, MediaModel mediaModel) {
        Media media = skuMediaMap.getMedia();
        if(media!=null){
            mediaModel.setImg(HttpRequestUtils.getUrl(media.getUrl()));
            mediaModel.setHash(media.getHash());
        }
    }

    private List<OptionModel> resultOptionModel(List optionIds,List optionValueIds,List<com.bifrost.model.option.OptionModel> models , ProductSku sku) {
        List<OptionModel> optionModels = new ArrayList<>();

        sku.getSkuOptionValues().forEach(skuOptionValue -> {
            ArrayList<OptionValueModel> optionValueModels = new ArrayList<>();
            OptionModel optionModel = new OptionModel();
            ProductOptionValue productOptionValue = skuOptionValue.getProductOptionValue();
            ProductOption productOption = productOptionValue.getProductOption();
            optionModel.setOptionXrefId(skuOptionValue.getSkuOptionValueXrefId());
            optionModel.setOptionValueName(productOptionValue.getAttributeValue());
            optionModel.setOptionValueNameId(productOptionValue.getProductOptionValueId());
            optionModel.setOptionName(productOption.getAttributeName());
            optionModel.setOptionNameId(productOption.getProductOptionId());
            optionModels.add(optionModel);

            if(!optionIds.contains(productOption.getProductOptionId())){
                optionValueModels.add(new OptionValueModel(productOptionValue.getProductOptionValueId(),productOptionValue.getAttributeValue(),skuOptionValue.getSkuOptionValueXrefId()));
                models.add(new com.bifrost.model.option.OptionModel(productOption.getProductOptionId(),productOption.getAttributeName(),optionValueModels));
                optionIds.add(productOption.getProductOptionId());
                optionValueIds.add(productOptionValue.getProductOptionValueId());

            }else {
                if(!optionValueIds.contains(productOptionValue.getProductOptionValueId())){
                    com.bifrost.model.option.OptionModel model = models.get(optionIds.indexOf(productOption.getProductOptionId()));
                    List<OptionValueModel> optionValues = model.getOptionValues();
                    optionValues.add(new OptionValueModel(productOptionValue.getProductOptionValueId(),productOptionValue.getAttributeValue(),skuOptionValue.getSkuOptionValueXrefId()));
                    optionValueIds.add(productOptionValue.getProductOptionValueId());
                }
            }

        });
        return optionModels;
    }

    private Product setRelatedProductInfo(User user , ProductBasicModel productBasicModel, Product product, MerchantStore store) {

        Category category;
        ProductBrand brand;
        Assert.notNull(category = categoryRepository.findOne(productBasicModel.getCategoryId()),"该商品选择分类不存在");
        Assert.notNull(brand = brandRepository.findOne(productBasicModel.getBrandId()),"该商品选择品牌不存在");;
        product.setProductCategory(category);
        product.setAvailable(false);  //新增为下架状态
        product.setMerchantId(store.getMerchantId());
        product.setProductBrand(brand);
        product.setCreatedTimestamp(new Date());
        product.setUpdatedTimestamp(new Date());
        product.setUpdatedBy(user.getAdminName());
        return product;

    }


    private ProductSku setDefaultSku(User user ,Product product, ProductBasicModel productBasicModel) {
        ProductSku defaultSku = product.getDefaultSku();
        if(defaultSku==null){
            defaultSku= new ProductSku();
        }
        BeanUtils.copyProperties(productBasicModel,defaultSku);
        /*defaultSku.setRetailPrice(basicModel.getDft_retailPrice());
        defaultSku.setSalePrice(basicModel.getDft_salePrice());
        defaultSku.setSkuCost(basicModel.getDft_skuCost());
        defaultSku.setQuantityAvailable(basicModel.getDft_quantityAvailable());
        defaultSku.setModel(basicModel.getDft_model());
        defaultSku.setSkuId(basicModel.getDft_skuId());*/
        defaultSku.setAvailable(productBasicModel.getDefaultAvaiable());
        defaultSku.setSkuName(product.getProductName());
        defaultSku.setSkuCode(product.getProductName());
        defaultSku.setSortOrder(0);
        defaultSku.setDefault(Boolean.TRUE);
        defaultSku.setProduct(product);
        defaultSku.setCategory(product.getProductCategory());
        defaultSku.setProductBrandId(product.getProductBrand().getProductBrandId());
        defaultSku.setUpdatedTimestamp(new Date());
        defaultSku.setUpdatedBy(user.getAdminName());
        if(productBasicModel.getSkuShipmentId()!=null){
            defaultSku.setShipmentTemplate(skuShipmentRepository.findOne(productBasicModel.getSkuShipmentId()));
        }
        return defaultSku;

    }


    @Deprecated
    private void newDefaultSkuMedia(ProductBasicModel productBasicModel, ProductSku defaultSku) {
        //添加默认sku的图文描述
        int sortOrder = 0;
        List<MediaModel> mediaModels = productBasicModel.getMediaModels();
        if (CollectionUtils.isNotEmpty(mediaModels)){
            for (MediaModel mediaModel : mediaModels) {
                if (null!=mediaModel&&mediaModel.getHash()!=null){
                    Media media = mediaRepository.findFirstByHash(mediaModel.getHash());
                    if(media!=null){
                        SkuMediaMap skuMediaMap = new SkuMediaMap();
                        BeanUtils.copyProperties(mediaModel,skuMediaMap);
                        skuMediaMap.setMedia(media);
                        skuMediaMap.setProductSku(defaultSku);
                        skuMediaMap.setSortOrder(++sortOrder);
                        skuMediaMapRepository.save(skuMediaMap);
                    }
                }
            }
        }
    }

    private ProductSku newProductSku(User user,Product product, ProductBasicModel productBasicModel, ProductSkuModel skuModel) {

        ProductSku sku = new ProductSku();
        // 设置sku统一属性
        BeanUtils.copyProperties(productBasicModel,sku);
        sku.setMerchantId(product.getMerchantId());
        sku.setDefault(Boolean.FALSE);
        sku.setProduct(product);
        sku.setProductBrandId(product.getProductBrand().getProductBrandId());
        sku.setCategory(product.getProductCategory());
        sku.setMerchantability(Boolean.TRUE);
        // 设置sku差异属性
        BeanUtils.copyProperties(skuModel, sku);
        if(productBasicModel.getSkuShipmentId()!=null){
         sku.setShipmentTemplate(skuShipmentRepository.findOne(productBasicModel.getSkuShipmentId()));
        }
        sku.setSkuCode(product.getProductName());
        sku.setSkuName(joiningTogetherSkuName(product,skuModel.getOptionModels()));
        sku.setCreatedTimestamp(new Date());
        sku.setUpdatedBy(user.getAdminName());
        sku.setUpdatedTimestamp(new Date());
        sku = productSkuRepository.save(sku);
        return sku;
    }

    private String joiningTogetherSkuName(Product product, List<OptionModel> optionModels) {
        StringBuffer sb = new StringBuffer(product.getProductName());
        if(!optionModels.isEmpty()){
            optionModels.forEach(optionModel -> {
                sb.append(" ").append(optionModel.getOptionValueName());
            });
        }
        return sb.toString();
    }


    private void newMediaAndOption(Map<Long, List<ProductOption>> listMap, ProductSkuModel skuModel, ProductSku sku) {

        // 设置规格图片
        if(CollectionUtils.isNotEmpty(skuModel.getMediaList())){
            for (MediaModel mediaModel : skuModel.getMediaList()) {
                addSkuMedia(sku, mediaModel);
            }
        }

        ArrayList<String> skuDescription = Lists.newArrayList();
        // 设置规格属性
        for (OptionModel optionModel : skuModel.getOptionModels()) {
            skuDescription.add(addOptionModels(sku, listMap, optionModel));
        }
        sku.setSkuDescription(skuDescription.isEmpty()?null:String.join(",",skuDescription));
        productSkuRepository.save(sku);
    }

    private void addSkuMedia(ProductSku sku, MediaModel mediaModel) {
        if (mediaModel.getImg() != null) {
            SkuMediaMap skuMediaMap = new SkuMediaMap();
            BeanUtils.copyProperties(mediaModel,skuMediaMap);
            skuMediaMap.setProductSku(sku);
            skuMediaMapRepository.save(skuMediaMap);
        }
    }

    private String addOptionModels(ProductSku sku, Map<Long, List<ProductOption>> listMap, OptionModel optionModel) {

        ProductOption productOption = null;
        Long optionNameId = optionModel.getOptionNameId();
        String optionName = optionModel.getOptionName();
        String optionValueName = optionModel.getOptionValueName();
        Long optionValueNameId = optionModel.getOptionValueNameId();
        List<ProductOption> options = listMap.get(optionNameId);

        if (CollectionUtils.isNotEmpty(options)) {
            productOption = options.get(0);
            Map<Long, List<ProductOptionValue>> collect = productOption.getProductOptionValues().stream().collect(Collectors.groupingBy(ProductOptionValue::getProductOptionValueId));
            List<ProductOptionValue> values = collect.get(optionValueNameId);
            ProductOptionValue productOptionValue = null;
            if (CollectionUtils.isNotEmpty(values)) {
                productOptionValue = values.get(0);
                /** 给指定sku 绑定规格*/
                SkuOptionValue skuOptionValue = new SkuOptionValue();
                skuOptionValue.setProductOptionValue(productOptionValue);
                skuOptionValue.setProductSku(sku);
                skuOptionValueRepository.save(skuOptionValue);
                // 正则匹配 过滤掉上版本错误数据
                return productOptionValue.getProductOptionValueId()+"";
            } else {
                throw new KnownRuntimeException("请先添加规格属性: %s ", optionValueName);
            }

        } else {
            throw new KnownRuntimeException("请先添加规格属性: %s ", optionValueName);
        }
    }

    private void imgRoNotBlank(ProductImgUploadRO uploadRO) {
        Asserts.notBlank(uploadRO.getTag(),"上传标签不可以为空..");
        if(CollectionUtils.isEmpty(uploadRO.getMainImgs())&&CollectionUtils.isEmpty(uploadRO.getDetailImgs())){
            throw new IllegalStateException("上传图片不可以为空");
        }
        Assert.isTrue(!(uploadRO.getProductId()==null&&uploadRO.getExternalId()==null),"商品id和商品编码必须选填其一");

    }

    public void addSkuMedia(ProductSku sku, String urlPath , String key ) {
        SkuMediaMap skuMediaMap = new SkuMediaMap();
        skuMediaMap.setImg(urlPath);
        skuMediaMap.setSortOrder(0);
        skuMediaMap.setProductSku(sku);
        skuMediaMap.setMapKey(key);
        if (skuMediaMapRepository.save(skuMediaMap)==null){
            log.error("sku保存图片失败");
            throw new RuntimeException("保存图片失败..");
        }
    }

}
